package com.songqi.common.timer;

import cn.hutool.core.date.DateUtil;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.*;




/**
 * @author: songqi(13776346982)
 */
@Configuration
@ConditionalOnBean(TimerEventHandle.class)
public class TimeWheel {

    /**
     * 每次转动的时间间隔，默认为1秒
     */
    private final long tickInterval = 1000;

    /**
     * 时间轮的大小，默认为60槽
     */
    private final int wheelSize = 60;

    private static List<CopyOnWriteArrayList<EventTimer>> timeWheel;
    private ScheduledExecutorService executor;


    private static final Logger log = LoggerFactory.getLogger(TimeWheel.class);

    @Resource
    private TimerEventHandle timerEventHandle;


    public synchronized void initialize() {
        log.info("初始化时间轮。");
        if (timeWheel == null) {
            timeWheel = new ArrayList<>();
            for (int i = 0; i < wheelSize; i++) {
                CopyOnWriteArrayList<EventTimer> innerList = new CopyOnWriteArrayList<>();
                timeWheel.add(innerList);
            }
            // 使用ThreadFactory来设置线程名字
            ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("TimeWheel-%d").build();

            executor = new ScheduledThreadPoolExecutor(1, threadFactory);

            executor.scheduleAtFixedRate(this::advance, tickInterval, tickInterval, TimeUnit.MILLISECONDS);
        }
    }
    @PreDestroy
    public void shutdown() {
        if (executor != null) {
            executor.shutdown();
        }
    }


    /**
     * 新增事件定时器至时间轮中
     * @param eventTimer
     */
    public void addEventTimer(EventTimer eventTimer) {
        Date startTime = eventTimer.getStartTime();
        Date endTime = eventTimer.getEndTime();
        Date nowTime = new Date();
        if(startTime.after(nowTime)){
            this.addToTimeWheel(eventTimer, startTime.getTime());
        }
        if(endTime.after(nowTime)){
            this.addToTimeWheel(eventTimer, endTime.getTime());
        }
    }


    /**
     * 更新事件定时器至时间轮中
     * @param oldEventTimer
     * @param newEventTimer
     */
    public void updateEventTimer(EventTimer oldEventTimer, EventTimer newEventTimer) {
        Date oldStartTime = oldEventTimer.getStartTime();
        Date oldEndTime = oldEventTimer.getEndTime();
        this.removeFromTimeWheel(oldEventTimer, oldStartTime.getTime());
        this.removeFromTimeWheel(oldEventTimer, oldEndTime.getTime());

        addEventTimer(newEventTimer);
    }



    private void advance() {
        Date nowTime = new Date();
        long nowTimeMillis = nowTime.getTime();
        String nowTimeFormat = DateUtil.format(nowTime, "yyyy-MM-dd HH:mm:ss");
        int currentWheelIndex = (int) ((nowTimeMillis / tickInterval) % wheelSize);
        List<EventTimer> eventTimerList = timeWheel.get(currentWheelIndex);

        for (EventTimer eventTimer : eventTimerList) {
            String startTime = DateUtil.format(eventTimer.getStartTime(), "yyyy-MM-dd HH:mm:ss");
            String endTime = DateUtil.format(eventTimer.getEndTime(), "yyyy-MM-dd HH:mm:ss");
            if(nowTimeFormat.equals(startTime)
                    || nowTimeFormat.equals(endTime)){
                try{
                    log.info("开始执行事件定时器[id={}, startTime={}, endTime={}, type={}]事件。",
                            eventTimer.getId(), DateUtil.format(eventTimer.getStartTime(), "yyyy-MM-dd HH:mm:ss"), DateUtil.format(eventTimer.getEndTime(), "yyyy-MM-dd HH:mm:ss"), eventTimer.getObjectType());
                    // 在这里实现更新事件定时器状态的逻辑
                    // 例如，更新数据库中事件定时器的状态为过期
                    timerEventHandle.handleEvent(eventTimer);
                }catch (Exception e){
                    log.error("执行定时更新操作失败。失败原因：{}", e.getMessage());
                }finally {
                    timeWheel.get(currentWheelIndex).remove(eventTimer);
                }
            }
        }
    }



    private void addToTimeWheel(EventTimer eventTimer, long futureTimeMillis){
        int wheelIndex = (int) ((futureTimeMillis / tickInterval) % wheelSize);
        timeWheel.get(wheelIndex).add(eventTimer);
        log.info("将事件定时器[id={}, startTime={}, endTime={}, type={}]添加到时间轮的第{}个槽中",
                eventTimer.getId(), DateUtil.format(eventTimer.getStartTime(), "yyyy-MM-dd HH:mm:ss"), DateUtil.format(eventTimer.getEndTime(), "yyyy-MM-dd HH:mm:ss"), eventTimer.getObjectType(), wheelIndex);
    }

    private void removeFromTimeWheel(EventTimer eventTimer, long futureTimeMillis){
        int oldWheelIndex = (int) ((futureTimeMillis / tickInterval) % wheelSize);
        timeWheel.get(oldWheelIndex).remove(eventTimer);
        log.info("将事件定时器[id={}, startTime={}, endTime={}, type={}]从时间轮的第{}个槽中移除",
                eventTimer.getId(), DateUtil.format(eventTimer.getStartTime(), "yyyy-MM-dd HH:mm:ss"), DateUtil.format(eventTimer.getEndTime(), "yyyy-MM-dd HH:mm:ss"), eventTimer.getObjectType(), oldWheelIndex);
    }


}
